using System;
using ParserGenerator.Extensions;

namespace ParserGenerator.CharacterMapping
{
    [Serializable]
    internal sealed class CharMapLink : IEquatable<CharMapLink>, IComparable<CharMapLink>, IComparable
    {
        public int Number { get; set; }
        public int Owner { get; set; }
        public int First { get; }
        public int Last { get; set; }

        public CharMapLink Previous { get; set; }
        public CharMapLink Next { get; set; }

        public CharMapLink(CharInterval item)
            : this(item.First, item.Last)
        {
        }

        public CharMapLink(int first, int last)
        {
            if (!CharInterval.Universal.Contains(first))
                throw new ArgumentOutOfRangeException(nameof(first), string.Format(SR.CharMustBeInRange, CharInterval.Universal));
            if (!CharInterval.Universal.Contains(last))
                throw new ArgumentOutOfRangeException(nameof(last), string.Format(SR.CharMustBeInRange, CharInterval.Universal));
            if (first > last)
                throw new ArgumentException(SR.FirstLastNotRange);
            First = first;
            Last = last;
        }

        public sealed override int GetHashCode()
        {
            return ICollectionExtensions.CombineHashCodes(First, Last);
        }

        public bool Equals(CharMapLink other)
        {
            return other != null && First == other.First && Last == other.Last;
        }

        public sealed override bool Equals(object obj)
        {
            return obj != null && Equals((CharMapLink)obj);
        }

        public int CompareTo(CharMapLink other)
        {
            if (other == null)
                return 1;
            else
                return First.CompareTo(other.First);
        }

        public int CompareTo(object obj)
        {
            if (obj == null)
                return 1;
            else if (obj is CharMapLink)
                return CompareTo((CharMapLink)obj);
            else
                throw new ArgumentException(SR.ArgumentMustBeCharpMapLink, nameof(obj));
        }

        public void AddAfter(CharMapLink node)
        {
            if (node == null)
                throw new ArgumentNullException(nameof(node));
            Previous = node;
            Next = node.Next;
            if (Next != null)
                Next.Previous = this;
            node.Next = this;
        }

        public void Pop()
        {
            if (Previous != null)
                Previous.Next = Next;
            if (Next != null)
                Next.Previous = Previous;
        }

        private static string Format(int c)
        {
            return c.AsSingleQuote();
        }

        public sealed override string ToString()
        {
            return Format(First) + " ... " + Format(Last);
        }
    }
}
